package caser.cairngorm.services.async
{
	import com.adobe.cairngorm.control.CairngormEvent;
	
	import flash.events.Event;
	
	import mx.collections.ArrayCollection;
	import mx.rpc.events.ResultEvent;
	
	
	public class ServiceMethodMultiCallCommandExecuter
	{
		private var eventStatusPairsCollection: ArrayCollection = new ArrayCollection();
		private var callBacksCollection: ArrayCollection = new ArrayCollection();
		
		public function ServiceMethodMultiCallCommandExecuter()
		{
			super();
		}

		public function execute(eventsArray: Array, callBacksArray: Array = null, isSequence: Boolean = true): void
		{
			var 
				isNewCycleStarting: Boolean = true;
			var 
				firstEventStatusPair: EventStatusPair = null;

			isNewCycleStarting = isNewCycleStarting && (this.eventStatusPairsCollection.length == 0);
			isNewCycleStarting = isNewCycleStarting && ((eventsArray != null) && (eventsArray.length > 0));

			for each (var callBackFunction: Function in callBacksArray)
			{
				this.callBacksCollection.addItem(callBackFunction);
			}//foreach
		
			for each (var event: ServiceMethodCallEvent in eventsArray)
			{
				// check if event has callbacks
				if (event.callBacksCollection == null)
					event.callBacksCollection = new ArrayCollection();
					
				event.callBacksCollection.addItem(requestCallBack);
				
				var 
					eventStatusPair: EventStatusPair = new EventStatusPair(event);
				
				this.eventStatusPairsCollection.addItem(eventStatusPair);
				
				if (firstEventStatusPair == null)
					firstEventStatusPair = eventStatusPair;
				
				if (!isSequence)
				{
					eventStatusPair.status = EventStatusPair.CNST_EVENT_STATUS_FIRED;
					eventStatusPair.event.dispatch();
				}//if
			}//foreach

			// execute first in a chain			
			if (isNewCycleStarting)
			{
				onStart();
				
				if (isSequence && (firstEventStatusPair != null))
				{
					firstEventStatusPair.status = EventStatusPair.CNST_EVENT_STATUS_FIRED;
					firstEventStatusPair.event.dispatch();
				}//if
			}//if
		}
		private function requestCallBack(cairngormEvent: CairngormEvent, event: Event): void
		{
			var 
				nextEventInChain: EventStatusPair = null;
			var 
				isDone: Boolean = true;
			
			// search for curent and next event
			for each (var eventStatusPair: EventStatusPair in this.eventStatusPairsCollection)
			{
				if (eventStatusPair.event == cairngormEvent)
				{
					eventStatusPair.status = 
						(event is ResultEvent) ? 
							EventStatusPair.CNST_EVENT_STATUS_DONE_SUCCESSFULLY : 
							EventStatusPair.CNST_EVENT_STATUS_DONE_FAILD;
				}
				else if (nextEventInChain == null)
				{
					if (eventStatusPair.status == EventStatusPair.CNST_EVENT_STATUS_QUERIED)
						nextEventInChain = eventStatusPair;
				}//if
				
				isDone = 
					isDone && 
						((eventStatusPair.status == EventStatusPair.CNST_EVENT_STATUS_DONE_FAILD) || 
						 (eventStatusPair.status == EventStatusPair.CNST_EVENT_STATUS_DONE_SUCCESSFULLY));
			}// foreach

			if (nextEventInChain != null)
			{
				nextEventInChain.status = EventStatusPair.CNST_EVENT_STATUS_FIRED;
				nextEventInChain.event.dispatch();
				return;
			}
			else if (!isDone)
			{
				// not all request are done
				return;
			}//if

			// all done call user funtions			
			var callBacksCollection: ArrayCollection = this.callBacksCollection;
			var eventStatuPairsCollection: ArrayCollection = this.eventStatusPairsCollection;
			
			// reset
			this.callBacksCollection = new ArrayCollection();
			this.eventStatusPairsCollection = new ArrayCollection(); 
			
			for each (var callBackFunction: Function in callBacksCollection)
			{
				callBackFunction.call(null, eventStatuPairsCollection);
			}//foreavch
			
			onDone();
		}
		
		protected virtual function onStart(): void
		{
		}
		protected virtual function onDone(): void
		{
		
		}
		
	}
}